import { updateNodeElement } from "../createDOMElement"
import { createTaskQueue, arrified, createStateNode, getTag } from "../misc"

const taskQueue = createTaskQueue()
// 子任务
let subTask = null
// 接收根节点的effects数组
let pendingCommit = null

// 根据根节点的effects，构建真实DOM树
const commitAllWork = fiber => {
  // 遍历effects
  fiber.effects.forEach(item => {
    // placement追加节点
    if (item.effectTag === 'placement') {
      let fiber = item
      let parent = fiber.parent
      // 如果父节点是类组件或函数组件，则继续查找父节点的父节点
      while (parent.tag === 'class_component' || parent.tag === 'function_component') {
        parent = parent.parent
      }
  
      if(fiber.tag === 'host_component') {
        parent.stateNode.appendChild(fiber.stateNode)
      }
    } 
    // update 更新DOM
    else if (item.effectTag === 'update') {
      if (item.type === item.altenate.type) {
        // 节点类型相同，进行节点更新操作
        updateNodeElement(item.stateNode, item, item.altenate)
      } else {
        // 节点类型不同，用新的DOM替换旧的DOM
        item.parent.stateNode.replaceChild(item.stateNode, item.altenate.stateNode)
      }
    }
    // delete 删除节点
    else if (item.effectTag === 'delete') {
      item.parent.stateNode.removeChild(item.stateNode)
    }
  })

  // 备份旧fiber对象
  fiber.stateNode.__rootFiberContainer = fiber
}

const getFirstTask = () => {
  const task = taskQueue.pop()

  // 设置根节点的Fiber
  return {
    props: task.props,
    stateNode: task.dom,
    tag: 'host_root', // 根节点
    effects: [], // 所有子节点的fiber对象，用于构建真实DOM
    child: null,
    altenate: task.dom.__rootFiberContainer // 在新的根节点中，可以获取到旧的Fiber对象
  }
}

const reconcileChildren = (fiber, children) => {
  // children有可能是数组，也有可能是对象，统一将children转成数组
  const arrifiedChildren = arrified(children)

  let index = 0
  let len = arrifiedChildren.length
  let element = null
  let newFiber = null
  let prevFiber = null

  let altenate = null
  if (fiber.altenate?.child) {
    altenate = fiber.altenate.child
  }
  // if (fiber.alternate && fiber.altenate.child) {
  //   // 给每个子节点设置altenate备份
  //   altenate = fiber.altenate.child
  //   console.log(altenate)
  // }
  // 将同级的节点全部设置Fiber对象
  while(index < len || altenate) {
    // 子级vDOM对象
    element = arrifiedChildren[index]

    // 如果altenate不存在，说明是首次渲染
    if (element && !altenate) {
      newFiber = {
        type: element.type,
        props: element.props,
        tag: getTag(element), // 通过vDom获取tag
        effects: [],
        effectTag: 'placement',
        parent: fiber
      }
      // 通过tag创建stateNode
      newFiber.stateNode = createStateNode(newFiber)
    }
    // 如果altenate存在，说明要进行更新操作
    else if (element && altenate) {
      newFiber = {
        type: element.type,
        props: element.props,
        tag: getTag(element), // 通过vDom获取tag
        effects: [],
        effectTag: 'update',
        parent: fiber,
        altenate
      }
      // 旧Fiber和新的vDom类型相同，直接使用旧的stateNode
      if (element.type === altenate.type) {
        newFiber.stateNode = altenate.stateNode
      } else {
        // 类型不同，直接创建一个stateNode
        newFiber.stateNode = createStateNode(newFiber)
      }
    }
    // 如果element不存在，altenate存在，说明要进行删除操作
    else if (!element && altenate) {
      altenate.effectTag = 'delete'
      fiber.effects.push(altenate)
    }

    // 如果是第一个子节点，才设置child属性，其他的子节点都是第一个子节点的兄弟节点
    if (index === 0) {
      fiber.child = newFiber
    } else if (element) {
      prevFiber.sibling = newFiber
    }

    if (altenate && altenate.sibling) {
      altenate = altenate.sibling
    } else {
      altenate = null
    }

    prevFiber = newFiber

    index++
  }

}

const executeTask = fiber => {
  // 设置子节点的Fiber
  if (fiber.tag === 'class_component') {
    reconcileChildren(fiber, fiber.stateNode.render())
  } else if (fiber.tag === 'function_component') {
    reconcileChildren(fiber, fiber.stateNode(fiber.props))
  } else {
    reconcileChildren(fiber, fiber.props.children)
  }
  // 如果有子节点，将这个子节点返回出去，继续下一轮executeTask
  if (fiber.child) {
    return fiber.child
  }
  // 如果有父节点，则去找当前节点的sibling，如果没有sibling，则继续向上查找
  let currentFiber = fiber
  while (currentFiber.parent) {
    // 设置effects数组，包含了所有的子节点Fiber对象
    currentFiber.parent.effects = currentFiber.parent.effects.concat(
      currentFiber.effects.concat([currentFiber])
    )
    if (currentFiber.sibling) {
      return currentFiber.sibling
    }
    currentFiber = currentFiber.parent
  }
  pendingCommit = currentFiber
}

// 循环执行任务
const workLoop = deadline => {
  // 如果子任务不存在，获取第一个任务
  if (!subTask) {
    subTask = getFirstTask()
  }

  // 当空余时间大于1ms，且任务存在，执行当前任务
  while(subTask && deadline.timeRemaining() > 1) {
    subTask = executeTask(subTask)
  }

  if (pendingCommit) {
    commitAllWork(pendingCommit)
  }
}

const performTask = deadline => {
  // 执行任务
  workLoop(deadline)
  // 如果任务存在或任务队列不为空，继续利用浏览器空闲时间执行任务
  if (subTask || !taskQueue.isEmpty()) {
    requestIdleCallback(performTask)
  }
}

export const render = (node, dom) => {

  /**
   * 1. 向任务队列中添加任务
   * 2. 在浏览器空闲时间执行
   */

  // 任务就是通过vDom 构建 fiber对象
  taskQueue.push({
    dom,
    props: { children: node }
  })

  requestIdleCallback(performTask)

}